#include "YaRRIncludes.h"


/************************************** Polite Request ***************************************
** I have put a lot of time and effort into YaRR. If you want to use some of the source     **
** please tell me. Anything used from YaRR must be open source, as is scripts.dll.          **
***************************************** Thank you *****************************************/


sqlite3 *YaRRDatabase::db;

void sin_glue(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
	double rad = sqlite3_value_double(argv[0]);
	if(rad >= 360 || rad <= -360)
	{
		char err[64];
		strcpy(err, "sin: value out of range");
		sqlite3_result_error(ctx, err, strlen(err));
		return;
	}

	rad = rad * (M_PI / 180);
	rad = sin(rad);
	sqlite3_result_double(ctx, rad);
}

void cos_glue(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
	double rad = sqlite3_value_double(argv[0]);
	if(rad >= 360 || rad <= -360)
	{
		char err[64];
		strcpy(err, "sin: value out of range");
		sqlite3_result_error(ctx, err, strlen(err));
		return;
	}

	rad = rad * (M_PI / 180);
	rad = cos(rad);
	sqlite3_result_double(ctx, rad);
}

void tan_glue(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
	double rad = sqlite3_value_double(argv[0]);
	if(rad >= 360 || rad <= -360)
	{
		char err[64];
		strcpy(err, "sin: value out of range");
		sqlite3_result_error(ctx, err, strlen(err));
		return;
	}

	rad = rad * (M_PI / 180);
	rad = tan(rad);
	sqlite3_result_double(ctx, rad);
}

void YaRRDatabase::Startup()
{
	DLOG;
	if(sqlite3_open("YaRR.db", &db) != 0)
	{
		YaRRFunctions::YaRRError("could not open database\n");
		return;
	}

	sqlite3_create_function(db, "sin", 1, SQLITE_ANY, 0, sin_glue, 0, 0);
	sqlite3_create_function(db, "cos", 1, SQLITE_ANY, 0, cos_glue, 0, 0); 
	sqlite3_create_function(db, "tan", 1, SQLITE_ANY, 0, tan_glue, 0, 0); 
}

void YaRRDatabase::Shutdown()
{
	DLOG;
	sqlite3_close(db);
}

const char *YaRRDatabase::Query(Stacker<YaRRDatabase::Row *> *l, const char *Format, ...)
{
	DLOG;
	va_list va;
	_crt_va_start(va, Format);
	char *buffer = sqlite3_vmprintf(Format, va);
	va_end(va);

	char *Error = 0;
	if(sqlite3_exec(db, buffer, Callback, (void *)l, &Error) != 0)
	{
		char *ret = YaRRFunctions::strdup2(Error);
		printf("Sqlite error: %s\n", Error);
		sqlite3_free(Error);
		sqlite3_free(buffer);
		if(l)
		{
			YaRRFunctions::DeleteList(l);
		}
		return ret;
	}
	sqlite3_free(buffer);
	return 0;
}

int YaRRDatabase::Callback(void *Data, int argc, char **ColumnData, char **Columns)
{
	DLOG;
	Stacker<YaRRDatabase::Row *> *l = (Stacker<YaRRDatabase::Row *> *)Data;
	if(!l)
	{
		return 0;
	}
	YaRRDatabase::Row *r = Alloc(YaRRDatabase::Row);
	r->Columns = Alloc(Stacker<YaRRDatabase::Column *>);
	for(int i = 0; i < argc; i++)
	{
		Column *c = Alloc(Column);
		
		c->Name = YaRRFunctions::strdup2(Columns[i]);
		c->Data = YaRRFunctions::strdup2(ColumnData[i] ? ColumnData[i] : "NULL");
		r->Columns->Push(c);
	}

	l->Push(r);
	return 0;
}

void YaRRDatabase::DeleteResult(Stacker<YaRRDatabase::Row *> *list)
{
	DLOG;
	if(!list)
	{
		return;
	}
	if(list->Empty())
	{
		return;
	}

	YaRRDatabase::Row *r;

	list->Reset();
	while(list->Iterate(&r))
	{
		YaRRDatabase::Column *c;
		r->Columns->Reset();
		while(r->Columns->Iterate(&c))
		{
			CDealloc(c->Name);
			CDealloc(c->Data);
		}
		YaRRFunctions::DeleteList(r->Columns);
		Dealloc(Stacker<Column *>, r->Columns);
	}

	YaRRFunctions::DeleteList(list);
	list->Clear();
}

char *YaRRDatabase::GetColumnData(const char *Name, Stacker<YaRRDatabase::Column *> *Row)
{
	DLOG;
	Column *c;
	Row->Reset();
	while(Row->Iterate(&c))
	{
		if(!c)
		{
			break;
		}
		if(strcmp(c->Name, Name) == 0)
		{	
			return c->Data;
		}
	}
	return "null";
}